﻿#include "tdx_file.h"

#include <fstream>
#include <ctype.h>
#include<cmath>
#include<map>

//#include <py_api/py_runner.h>
//#include <glog/logging.h>
#include <forward_list>
namespace fs = std::filesystem;

fs::path TdxFileStore::get_filepath(Exchange exchangeid, std::string symbol, BarSize barsize)
{
	auto p = fs::path(dir);
		p /= "vipdoc";
		std::string pre ;
		if (exchangeid == (Exchange::SH))
		{
			p /= "sh";
			pre = "sh";
		}
		else if (exchangeid == (Exchange::SZ))
		{
			p /= "sz";
			pre = "sz";
		}
		else
		{
//			LOG(FATAL) << "not supported exchange";
			std::terminate();
			return p;
		}
			
		if (barsize == BarSize::Day1)
		{
			p /= "lday";
			p /=  pre+symbol + ".day";
		}
		else if (barsize == BarSize::Min1) {
			p /= "minline";
			p /= pre+ symbol + ".lc1";
		}
		else
		{
			//LOG(FATAL) << "not supported barsize";
			std::terminate();
			return p;
		}


	return p;
}

fs::path TdxFileStore::get_path(Exchange exchangeid, BarSize barsize)
{
	return get_filepath((exchangeid),"000000", barsize).parent_path();
}

uint16_t TdxFileStore::row_size(BarSize barsize)
{
	return 32;
}

std::forward_list<std::string> TdxFileStore::get_symbols(Exchange exchange, BarSize bs)
{
	auto v = std::forward_list<std::string>();
	auto p=get_filepath((exchange),"000000",bs);
	for (auto& child : fs::directory_iterator(p.parent_path())) {
		v.push_front(child.path().filename().string());
	}
	return v;
}

std::unordered_map<uint32_t, int32_t> TdxFileStore::get_trading_date(std::vector<char>* b)
{
	auto v = std::unordered_map<uint32_t, int32_t>();
	int rowcnt = b->size() / row_size(BarSize::Day1);
	if (rowcnt < 1)
	{
		std::cout << "error read trading date";
		return v;
	}
	v.reserve(rowcnt);
	for (uint32_t i = 0; i < rowcnt; i++) {
		v[((tdx_1d_t*)(b->data() + row_size(BarSize::Day1) * i))->date] = i;
	}

	return v;
}

std::unordered_map<uint32_t, int32_t> TdxFileStore::get_trading_date(std::string symbol)
{
	auto v = std::unordered_map<uint32_t, int32_t>();
	if (symbol == "-")
		symbol = "000001";
	auto b = read_bytes((Exchange::SH), symbol, BarSize::Day1);
	int rowcnt = b.size() / sizeof(tdx_1d_t);
	if (rowcnt < 1)
	{
		std::cout << "error read trading date";
		return v;
	}
	v.reserve(rowcnt);
	for (uint32_t i = 0; i < rowcnt; i++) {
		v[((tdx_1d_t*)(b.data() + sizeof(tdx_1d_t) * i))->date] = i;
	}
	trading_range.first = ((tdx_1d_t*)(b.data()))->date;
	trading_range.second = ((tdx_1d_t*)(b.data() + sizeof(tdx_1d_t) * (rowcnt - 1)))->date;
	printf("trading date range(%d,%d),length:%zd\n", trading_range.first, trading_range.second, v.size());
	return v;
}

fs::directory_iterator TdxFileStore::symbol_iterator(Exchange e,BarSize bs)
{
	auto p = get_filepath((e), "000000", bs);
	return  fs::directory_iterator(p.parent_path());
}

std::pair<uint32_t, uint32_t> TdxFileStore::get_range(std::vector<char>* d)
{
	std::pair<uint32_t, uint32_t> v;
	v.first = *(uint32_t*)(d->data());
	v.second = *(uint32_t*)(d->data()+d->size()-32);

	return v;
}

std::vector<Bar> TdxFileStore::get_daybar(Exchange exchange, std::string symbol)
{
	std::vector<Bar> v;
	auto b=read_bytes(exchange, symbol, BarSize::Day1);
	if (b.size() == 0)
	{			
		return v; 
	}

	if (b.size() % 32 != 0)
	{
	//	LOG(WARNING) << "tdx daybar file broken"<< Exchange_code[int(exchange)]<<symbol<< b.size()<<"bytes";
		return v;
	}
	v.resize(b.size() / 32);
	for (int i=0; i < v.size(); i++) {
		uint32_t day= *(uint32_t*)(b.data() + i * 32);
		v[i].time = DateTime::day2time(day);
		v[i].open = *(uint32_t*)(b.data() + i * 32+4);
		v[i].high = *(uint32_t*)(b.data() + i * 32 + 8);
		v[i].low = *(uint32_t*)(b.data() + i * 32 + 12);
		v[i].close = *(uint32_t*)(b.data() + i * 32 + 16);
		v[i].volume = *(uint32_t*)(b.data() + i * 32 + 24);
		v[i].amount= *(float*)(b.data() + i * 32 + 20);
	}
	return v;
}

std::map<uint32_t, std::vector<MinuteBar>> TdxFileStore::get_minutebar(Exchange exchange, std::string symbol)
{
	std::map<uint32_t, std::vector<MinuteBar>> bars;
	auto b = read_bytes(exchange, symbol, BarSize::Min1);
	if (b.size() < 32 || b.size() % 32 != 0)
	{

		return bars;
	}
	int minbarcnt=b.size() / 32;
	
	BarDateTime firstday,day ;
	firstday= *(uint32_t*)(b.data());

	int barperday = 240;//开始循环统计一天有多少根bar
	int indexofday=-1;
	uint32_t preday = 0;
	//迭代每行分钟K线，寻找日期发生变化的那个
	for (int i = 0; i < minbarcnt; i++) {
		day = *(uint32_t*)(b.data() + i * row_size(BarSize::Min1));
		uint32_t timestamp= DateTime::day2time(day.date());
		uint16_t min = day.min();

		if (preday==0||timestamp == preday)
			indexofday++;
		else {
			indexofday = 0;
		}
			
		preday = timestamp;
		

		if (bars[timestamp].capacity() <240) {
			bars[timestamp].reserve(240);
		}

		if (indexofday >= bars[timestamp].size())
			bars[timestamp].resize(indexofday + 1);
		bars.at(timestamp)[indexofday].min = min;
		bars.at(timestamp)[indexofday].open = std::round(*((float*)(b.data() + i * 32 + 4)) * 100);
		bars.at(timestamp)[indexofday].high = std::round(*((float*)(b.data() + i * 32 + 8)) * 100);
		bars.at(timestamp)[indexofday].low = std::round(*((float*)(b.data() + i * 32 + 12)) * 100);
		bars.at(timestamp)[indexofday].close = std::round(*((float*)(b.data() + i * 32 + 16)) * 100);
		bars.at(timestamp)[indexofday].amount = *((float*)(b.data() + i * 32 + 20));
		bars.at(timestamp)[indexofday].volume = *((uint32_t*)(b.data() + i * 32 + 24));
	}

	
	return  bars;
}



